home *** CD-ROM | disk | FTP | other *** search
/ The CICA Windows Explosion! / The CICA Windows Explosion! - Disc 2.iso / programr / dpmigcc5.zip / RSX / SOURCE / FPU-EMU / REG_LD_S.C < prev    next >
C/C++ Source or Header  |  1994-05-27  |  37KB  |  1,464 lines

  1. /*---------------------------------------------------------------------------+
  2.  |  reg_ld_str.c                                                             |
  3.  |                                                                           |
  4.  | All of the functions which transfer data between user memory and FPU_REGs.|
  5.  |                                                                           |
  6.  | Copyright (C) 1992,1993,1994                                              |
  7.  |                       W. Metzenthen, 22 Parker St, Ormond, Vic 3163,      |
  8.  |                       Australia.  E-mail   billm@vaxc.cc.monash.edu.au    |
  9.  |                                                                           |
  10.  |                                                                           |
  11.  +---------------------------------------------------------------------------*/
  12.  
  13. /*---------------------------------------------------------------------------+
  14.  | Note:                                                                     |
  15.  |    The file contains code which accesses user memory.                     |
  16.  |    Emulator static data may change when user memory is accessed, due to   |
  17.  |    other processes using the emulator while swapping is in progress.      |
  18.  +---------------------------------------------------------------------------*/
  19.  
  20. #include <asm/segment.h>
  21.  
  22. #include "fpu_system.h"
  23. #include "exception.h"
  24. #include "reg_constant.h"
  25. #include "fpu_emu.h"
  26. #include "control_w.h"
  27. #include "status_w.h"
  28.  
  29.  
  30. #define EXTENDED_Ebias 0x3fff
  31. #define EXTENDED_Emin (-0x3ffe)  /* smallest valid exponent */
  32.  
  33. #define DOUBLE_Emax 1023         /* largest valid exponent */
  34. #define DOUBLE_Ebias 1023
  35. #define DOUBLE_Emin (-1022)      /* smallest valid exponent */
  36.  
  37. #define SINGLE_Emax 127          /* largest valid exponent */
  38. #define SINGLE_Ebias 127
  39. #define SINGLE_Emin (-126)       /* smallest valid exponent */
  40.  
  41. static void write_to_extended(FPU_REG *rp, char *d);
  42.  
  43. FPU_REG FPU_loaded_data;
  44.  
  45.  
  46. /* Get a long double from user memory */
  47. int reg_load_extended(void)
  48. {
  49.   long double *s = (long double *)FPU_data_address;
  50.   unsigned long sigl, sigh, exp;
  51.  
  52.   RE_ENTRANT_CHECK_OFF;
  53.   FPU_verify_area(VERIFY_READ, s, 10);
  54.   /* Use temporary variables here because FPU_loaded data is
  55.      static and hence re-entrancy problems can arise */
  56.   sigl = get_fs_long((unsigned long *) s);
  57.   sigh = get_fs_long(1 + (unsigned long *) s);
  58.   exp = get_fs_word(4 + (unsigned short *) s);
  59.   RE_ENTRANT_CHECK_ON;
  60.  
  61.   FPU_loaded_data.tag = TW_Valid;   /* Default */
  62.   FPU_loaded_data.sigl = sigl;
  63.   FPU_loaded_data.sigh = sigh;
  64.   if (exp & 0x8000)
  65.     FPU_loaded_data.sign = SIGN_NEG;
  66.   else
  67.     FPU_loaded_data.sign = SIGN_POS;
  68.   exp &= 0x7fff;
  69.   FPU_loaded_data.exp = exp - EXTENDED_Ebias + EXP_BIAS;
  70.  
  71.   /* Assume that optimisation can keep sigl, sigh, and exp in
  72.      registers, otherwise it would be more efficient to work
  73.      with FPU_loaded_data (which is static) here. */
  74.   if ( exp == 0 )
  75.     {
  76.       if ( !(sigh | sigl) )
  77.     {
  78.       FPU_loaded_data.tag = TW_Zero;
  79.       return 0;
  80.     }
  81.       /* The number is a de-normal or pseudodenormal. */
  82.       if (sigh & 0x80000000)
  83.     {
  84.       /* Is a pseudodenormal. */
  85.       /* Convert it for internal use. */
  86.       /* This is non-80486 behaviour because the number
  87.          loses its 'denormal' identity. */
  88.       FPU_loaded_data.exp++;
  89.       return 1;
  90.     }
  91.       else
  92.     {
  93.       /* Is a denormal. */
  94.       /* Convert it for internal use. */
  95.       FPU_loaded_data.exp++;
  96.       normalize_nuo(&FPU_loaded_data);
  97.       return 0;
  98.     }
  99.     }
  100.   else if ( exp == 0x7fff )
  101.     {
  102.       if ( !((sigh ^ 0x80000000) | sigl) )
  103.     {
  104.       /* Matches the bit pattern for Infinity. */
  105.       FPU_loaded_data.exp = EXP_Infinity;
  106.       FPU_loaded_data.tag = TW_Infinity;
  107.       return 0;
  108.     }
  109.  
  110.       FPU_loaded_data.exp = EXP_NaN;
  111.       FPU_loaded_data.tag = TW_NaN;
  112.       if ( !(sigh & 0x80000000) )
  113.     {
  114.       /* NaNs have the ms bit set to 1. */
  115.       /* This is therefore an Unsupported NaN data type. */
  116.       /* This is non 80486 behaviour */
  117.       /* This should generate an Invalid Operand exception
  118.          later, so we convert it to a SNaN */
  119.       FPU_loaded_data.sigh = 0x80000000;
  120.       FPU_loaded_data.sigl = 0x00000001;
  121.       FPU_loaded_data.sign = SIGN_NEG;
  122.       return 1;
  123.     }
  124.       return 0;
  125.     }
  126.  
  127.   if ( !(sigh & 0x80000000) )
  128.     {
  129.       /* Unsupported data type. */
  130.       /* Valid numbers have the ms bit set to 1. */
  131.       /* Unnormal. */
  132.       /* Convert it for internal use. */
  133.       /* This is non-80486 behaviour */
  134.       /* This should generate an Invalid Operand exception
  135.      later, so we convert it to a SNaN */
  136.       FPU_loaded_data.sigh = 0x80000000;
  137.       FPU_loaded_data.sigl = 0x00000001;
  138.       FPU_loaded_data.sign = SIGN_NEG;
  139.       FPU_loaded_data.exp = EXP_NaN;
  140.       FPU_loaded_data.tag = TW_NaN;
  141.       return 1;
  142.     }
  143.   return 0;
  144. }
  145.  
  146.  
  147. /* Get a double from user memory */
  148. int reg_load_double(void)
  149. {
  150.   double *dfloat = (double *)FPU_data_address;
  151.   int exp;
  152.   unsigned m64, l64;
  153.  
  154.   RE_ENTRANT_CHECK_OFF;
  155.   FPU_verify_area(VERIFY_READ, dfloat, 8);
  156.   m64 = get_fs_long(1 + (unsigned long *) dfloat);
  157.   l64 = get_fs_long((unsigned long *) dfloat);
  158.   RE_ENTRANT_CHECK_ON;
  159.  
  160.   if (m64 & 0x80000000)
  161.     FPU_loaded_data.sign = SIGN_NEG;
  162.   else
  163.     FPU_loaded_data.sign = SIGN_POS;
  164.   exp = ((m64 & 0x7ff00000) >> 20) - DOUBLE_Ebias;
  165.   m64 &= 0xfffff;
  166.   if (exp > DOUBLE_Emax)
  167.     {
  168.       /* Infinity or NaN */
  169.       if ((m64 == 0) && (l64 == 0))
  170.     {
  171.       /* +- infinity */
  172.       FPU_loaded_data.sigh = 0x80000000;
  173.       FPU_loaded_data.sigl = 0x00000000;
  174.       FPU_loaded_data.exp = EXP_Infinity;
  175.       FPU_loaded_data.tag = TW_Infinity;
  176.       return 0;
  177.     }
  178.       else
  179.     {
  180.       /* Must be a signaling or quiet NaN */
  181.       FPU_loaded_data.exp = EXP_NaN;
  182.       FPU_loaded_data.tag = TW_NaN;
  183.       FPU_loaded_data.sigh = (m64 << 11) | 0x80000000;
  184.       FPU_loaded_data.sigh |= l64 >> 21;
  185.       FPU_loaded_data.sigl = l64 << 11;
  186.       return 0; /* The calling function must look for NaNs */
  187.     }
  188.     }
  189.   else if ( exp < DOUBLE_Emin )
  190.     {
  191.       /* Zero or de-normal */
  192.       if ((m64 == 0) && (l64 == 0))
  193.     {
  194.       /* Zero */
  195.       int c = FPU_loaded_data.sign;
  196.       reg_move(&CONST_Z, &FPU_loaded_data);
  197.       FPU_loaded_data.sign = c;
  198.       return 0;
  199.     }
  200.       else
  201.     {
  202.       /* De-normal */
  203.       FPU_loaded_data.exp = DOUBLE_Emin + EXP_BIAS;
  204.       FPU_loaded_data.tag = TW_Valid;
  205.       FPU_loaded_data.sigh = m64 << 11;
  206.       FPU_loaded_data.sigh |= l64 >> 21;
  207.       FPU_loaded_data.sigl = l64 << 11;
  208.       normalize_nuo(&FPU_loaded_data);
  209.       return denormal_operand();
  210.     }
  211.     }
  212.   else
  213.     {
  214.       FPU_loaded_data.exp = exp + EXP_BIAS;
  215.       FPU_loaded_data.tag = TW_Valid;
  216.       FPU_loaded_data.sigh = (m64 << 11) | 0x80000000;
  217.       FPU_loaded_data.sigh |= l64 >> 21;
  218.       FPU_loaded_data.sigl = l64 << 11;
  219.  
  220.       return 0;
  221.     }
  222. }
  223.  
  224.  
  225. /* Get a float from user memory */
  226. int reg_load_single(void)
  227. {
  228.   float *single = (float *)FPU_data_address;
  229.   unsigned m32;
  230.   int exp;
  231.  
  232.   RE_ENTRANT_CHECK_OFF;
  233.   FPU_verify_area(VERIFY_READ, single, 4);
  234.   m32 = get_fs_long((unsigned long *) single);
  235.   RE_ENTRANT_CHECK_ON;
  236.  
  237.   if (m32 & 0x80000000)
  238.     FPU_loaded_data.sign = SIGN_NEG;
  239.   else
  240.     FPU_loaded_data.sign = SIGN_POS;
  241.   if (!(m32 & 0x7fffffff))
  242.     {
  243.       /* Zero */
  244.       int c = FPU_loaded_data.sign;
  245.       reg_move(&CONST_Z, &FPU_loaded_data);
  246.       FPU_loaded_data.sign = c;
  247.       return 0;
  248.     }
  249.   exp = ((m32 & 0x7f800000) >> 23) - SINGLE_Ebias;
  250.   m32 = (m32 & 0x7fffff) << 8;
  251.   if ( exp < SINGLE_Emin )
  252.     {
  253.       /* De-normals */
  254.       FPU_loaded_data.exp = SINGLE_Emin + EXP_BIAS;
  255.       FPU_loaded_data.tag = TW_Valid;
  256.       FPU_loaded_data.sigh = m32;
  257.       FPU_loaded_data.sigl = 0;
  258.       normalize_nuo(&FPU_loaded_data);
  259.       return denormal_operand();
  260.     }
  261.   else if ( exp > SINGLE_Emax )
  262.     {
  263.     /* Infinity or NaN */
  264.       if ( m32 == 0 )
  265.     {
  266.       /* +- infinity */
  267.       FPU_loaded_data.sigh = 0x80000000;
  268.       FPU_loaded_data.sigl = 0x00000000;
  269.       FPU_loaded_data.exp = EXP_Infinity;
  270.       FPU_loaded_data.tag = TW_Infinity;
  271.       return 0;
  272.     }
  273.       else
  274.     {
  275.       /* Must be a signaling or quiet NaN */
  276.       FPU_loaded_data.exp = EXP_NaN;
  277.       FPU_loaded_data.tag = TW_NaN;
  278.       FPU_loaded_data.sigh = m32 | 0x80000000;
  279.       FPU_loaded_data.sigl = 0;
  280.       return 0; /* The calling function must look for NaNs */
  281.     }
  282.     }
  283.   else
  284.     {
  285.       FPU_loaded_data.exp = exp + EXP_BIAS;
  286.       FPU_loaded_data.sigh = m32 | 0x80000000;
  287.       FPU_loaded_data.sigl = 0;
  288.       FPU_loaded_data.tag = TW_Valid;
  289.       return 0;
  290.     }
  291. }
  292.  
  293.  
  294. /* Get a long long from user memory */
  295. void reg_load_int64(void)
  296. {
  297.   long long *_s = (long long *)FPU_data_address;
  298.   int e;
  299.   long long s;
  300.  
  301.   RE_ENTRANT_CHECK_OFF;
  302.   FPU_verify_area(VERIFY_READ, _s, 8);
  303.   ((unsigned long *)&s)[0] = get_fs_long((unsigned long *) _s);
  304.   ((unsigned long *)&s)[1] = get_fs_long(1 + (unsigned long *) _s);
  305.   RE_ENTRANT_CHECK_ON;
  306.  
  307.   if (s == 0)
  308.     { reg_move(&CONST_Z, &FPU_loaded_data); return; }
  309.  
  310.   if (s > 0)
  311.     FPU_loaded_data.sign = SIGN_POS;
  312.   else
  313.   {
  314.     s = -s;
  315.     FPU_loaded_data.sign = SIGN_NEG;
  316.   }
  317.  
  318.   e = EXP_BIAS + 63;
  319.   significand(&FPU_loaded_data) = s;
  320.   FPU_loaded_data.exp = e;
  321.   FPU_loaded_data.tag = TW_Valid;
  322.   normalize_nuo(&FPU_loaded_data);
  323. }
  324.  
  325.  
  326. /* Get a long from user memory */
  327. void reg_load_int32(void)
  328. {
  329.   long *_s = (long *)FPU_data_address;
  330.   long s;
  331.   int e;
  332.  
  333.   RE_ENTRANT_CHECK_OFF;
  334.   FPU_verify_area(VERIFY_READ, _s, 4);
  335.   s = (long)get_fs_long((unsigned long *) _s);
  336.   RE_ENTRANT_CHECK_ON;
  337.  
  338.   if (s == 0)
  339.     { reg_move(&CONST_Z, &FPU_loaded_data); return; }
  340.  
  341.   if (s > 0)
  342.     FPU_loaded_data.sign = SIGN_POS;
  343.   else
  344.   {
  345.     s = -s;
  346.     FPU_loaded_data.sign = SIGN_NEG;
  347.   }
  348.  
  349.   e = EXP_BIAS + 31;
  350.   FPU_loaded_data.sigh = s;
  351.   FPU_loaded_data.sigl = 0;
  352.   FPU_loaded_data.exp = e;
  353.   FPU_loaded_data.tag = TW_Valid;
  354.   normalize_nuo(&FPU_loaded_data);
  355. }
  356.  
  357.  
  358. /* Get a short from user memory */
  359. void reg_load_int16(void)
  360. {
  361.   short *_s = (short *)FPU_data_address;
  362.   int s, e;
  363.  
  364.   RE_ENTRANT_CHECK_OFF;
  365.   FPU_verify_area(VERIFY_READ, _s, 2);
  366.   /* Cast as short to get the sign extended. */
  367.   s = (short)get_fs_word((unsigned short *) _s);
  368.   RE_ENTRANT_CHECK_ON;
  369.  
  370.   if (s == 0)
  371.     { reg_move(&CONST_Z, &FPU_loaded_data); return; }
  372.  
  373.   if (s > 0)
  374.     FPU_loaded_data.sign = SIGN_POS;
  375.   else
  376.   {
  377.     s = -s;
  378.     FPU_loaded_data.sign = SIGN_NEG;
  379.   }
  380.  
  381.   e = EXP_BIAS + 15;
  382.   FPU_loaded_data.sigh = s << 16;
  383.  
  384.   FPU_loaded_data.sigl = 0;
  385.   FPU_loaded_data.exp = e;
  386.   FPU_loaded_data.tag = TW_Valid;
  387.   normalize_nuo(&FPU_loaded_data);
  388. }
  389.  
  390.  
  391. /* Get a packed bcd array from user memory */
  392. void reg_load_bcd(void)
  393. {
  394.   char *s = (char *)FPU_data_address;
  395.   int pos;
  396.   unsigned char bcd;
  397.   long long l=0;
  398.  
  399.   RE_ENTRANT_CHECK_OFF;
  400.   FPU_verify_area(VERIFY_READ, s, 10);
  401.   RE_ENTRANT_CHECK_ON;
  402.   for ( pos = 8; pos >= 0; pos--)
  403.     {
  404.       l *= 10;
  405.       RE_ENTRANT_CHECK_OFF;
  406.       bcd = (unsigned char)get_fs_byte((unsigned char *) s+pos);
  407.       RE_ENTRANT_CHECK_ON;
  408.       l += bcd >> 4;
  409.       l *= 10;
  410.       l += bcd & 0x0f;
  411.     }
  412.   
  413.   /* Finish all access to user memory before putting stuff into
  414.      the static FPU_loaded_data */
  415.   RE_ENTRANT_CHECK_OFF;
  416.   FPU_loaded_data.sign =
  417.     ((unsigned char)get_fs_byte((unsigned char *) s+9)) & 0x80 ?
  418.       SIGN_NEG : SIGN_POS;
  419.   RE_ENTRANT_CHECK_ON;
  420.  
  421.   if (l == 0)
  422.     {
  423.       char sign = FPU_loaded_data.sign;
  424.       reg_move(&CONST_Z, &FPU_loaded_data);
  425.       FPU_loaded_data.sign = sign;
  426.     }
  427.   else
  428.     {
  429.       significand(&FPU_loaded_data) = l;
  430.       FPU_loaded_data.exp = EXP_BIAS + 63;
  431.       FPU_loaded_data.tag = TW_Valid;
  432.       normalize_nuo(&FPU_loaded_data);
  433.     }
  434. }
  435.  
  436. /*===========================================================================*/
  437.  
  438. /* Put a long double into user memory */
  439. int reg_store_extended(void)
  440. {
  441.   /*
  442.     The only exception raised by an attempt to store to an
  443.     extended format is the Invalid Stack exception, i.e.
  444.     attempting to store from an empty register.
  445.    */
  446.   long double *d = (long double *)FPU_data_address;
  447.  
  448.   if ( FPU_st0_tag != TW_Empty )
  449.     {
  450.       RE_ENTRANT_CHECK_OFF;
  451.       FPU_verify_area(VERIFY_WRITE, d, 10);
  452.       RE_ENTRANT_CHECK_ON;
  453.       write_to_extended(FPU_st0_ptr, (char *) FPU_data_address);
  454.       return 1;
  455.     }
  456.  
  457.   /* Empty register (stack underflow) */
  458.   EXCEPTION(EX_StackUnder);
  459.   if ( control_word & CW_Invalid )
  460.     {
  461.       /* The masked response */
  462.       /* Put out the QNaN indefinite */
  463.       RE_ENTRANT_CHECK_OFF;
  464.       FPU_verify_area(VERIFY_WRITE,d,10);
  465.       put_fs_long(0, (unsigned long *) d);
  466.       put_fs_long(0xc0000000, 1 + (unsigned long *) d);
  467.       put_fs_word(0xffff, 4 + (short *) d);
  468.       RE_ENTRANT_CHECK_ON;
  469.       return 1;
  470.     }
  471.   else
  472.     return 0;
  473.  
  474. }
  475.  
  476.  
  477. /* Put a double into user memory */
  478. int reg_store_double(void)
  479. {
  480.   double *dfloat = (double *)FPU_data_address;
  481.   unsigned long l[2];
  482.   unsigned long increment = 0;    /* avoid gcc warnings */
  483.  
  484.   if (FPU_st0_tag == TW_Valid)
  485.     {
  486.       int exp;
  487.       FPU_REG tmp;
  488.  
  489.       reg_move(FPU_st0_ptr, &tmp);
  490.       exp = tmp.exp - EXP_BIAS;
  491.  
  492.       if ( exp < DOUBLE_Emin )     /* It may be a denormal */
  493.     {
  494.       int precision_loss;
  495.  
  496.       /* A denormal will always underflow. */
  497. #ifndef PECULIAR_486
  498.       /* An 80486 is supposed to be able to generate
  499.          a denormal exception here, but... */
  500.       if ( FPU_st0_ptr->exp <= EXP_UNDER )
  501.         {
  502.           /* Underflow has priority. */
  503.           if ( control_word & CW_Underflow )
  504.         denormal_operand();
  505.         }
  506. #endif PECULIAR_486
  507.  
  508.       tmp.exp += -DOUBLE_Emin + 52;  /* largest exp to be 51 */
  509.  
  510.       if ( (precision_loss = round_to_int(&tmp)) )
  511.         {
  512. #ifdef PECULIAR_486
  513.           /* Did it round to a non-denormal ? */
  514.           /* This behaviour might be regarded as peculiar, it appears
  515.          that the 80486 rounds to the dest precision, then
  516.          converts to decide underflow. */
  517.           if ( !((tmp.sigh == 0x00100000) && (tmp.sigl == 0) &&
  518.           (FPU_st0_ptr->sigl & 0x000007ff)) )
  519. #endif PECULIAR_486
  520.         {
  521.           EXCEPTION(EX_Underflow);
  522.           /* This is a special case: see sec 16.2.5.1 of
  523.              the 80486 book */
  524.           if ( !(control_word & CW_Underflow) )
  525.             return 0;
  526.         }
  527.           EXCEPTION(precision_loss);
  528.           if ( !(control_word & CW_Precision) )
  529.         return 0;
  530.         }
  531.       l[0] = tmp.sigl;
  532.       l[1] = tmp.sigh;
  533.     }
  534.       else
  535.     {
  536.       if ( tmp.sigl & 0x000007ff )
  537.         {
  538.           switch (control_word & CW_RC)
  539.         {
  540.         case RC_RND:
  541.           /* Rounding can get a little messy.. */
  542.           increment = ((tmp.sigl & 0x7ff) > 0x400) |  /* nearest */
  543.             ((tmp.sigl & 0xc00) == 0xc00);            /* odd -> even */
  544.           break;
  545.         case RC_DOWN:   /* towards -infinity */
  546.           increment = (tmp.sign == SIGN_POS) ? 0 : tmp.sigl & 0x7ff;
  547.           break;
  548.         case RC_UP:     /* towards +infinity */
  549.           increment = (tmp.sign == SIGN_POS) ? tmp.sigl & 0x7ff : 0;
  550.           break;
  551.         case RC_CHOP:
  552.           increment = 0;
  553.           break;
  554.         }
  555.       
  556.           /* Truncate the mantissa */
  557.           tmp.sigl &= 0xfffff800;
  558.       
  559.           if ( increment )
  560.         {
  561.           set_precision_flag_up();
  562.  
  563.           if ( tmp.sigl >= 0xfffff800 )
  564.             {
  565.               /* the sigl part overflows */
  566.               if ( tmp.sigh == 0xffffffff )
  567.             {
  568.               /* The sigh part overflows */
  569.               tmp.sigh = 0x80000000;
  570.               exp++;
  571.               if (exp >= EXP_OVER)
  572.                 goto overflow;
  573.             }
  574.               else
  575.             {
  576.               tmp.sigh ++;
  577.             }
  578.               tmp.sigl = 0x00000000;
  579.             }
  580.           else
  581.             {
  582.               /* We only need to increment sigl */
  583.               tmp.sigl += 0x00000800;
  584.             }
  585.         }
  586.           else
  587.         set_precision_flag_down();
  588.         }
  589.       
  590.       l[0] = (tmp.sigl >> 11) | (tmp.sigh << 21);
  591.       l[1] = ((tmp.sigh >> 11) & 0xfffff);
  592.  
  593.       if ( exp > DOUBLE_Emax )
  594.         {
  595.         overflow:
  596.           EXCEPTION(EX_Overflow);
  597.           if ( !(control_word & CW_Overflow) )
  598.         return 0;
  599.           set_precision_flag_up();
  600.           if ( !(control_word & CW_Precision) )
  601.         return 0;
  602.  
  603.           /* This is a special case: see sec 16.2.5.1 of the 80486 book */
  604.           /* Overflow to infinity */
  605.           l[0] = 0x00000000;    /* Set to */
  606.           l[1] = 0x7ff00000;    /* + INF */
  607.         }
  608.       else
  609.         {
  610.           /* Add the exponent */
  611.           l[1] |= (((exp+DOUBLE_Ebias) & 0x7ff) << 20);
  612.         }
  613.     }
  614.     }
  615.   else if (FPU_st0_tag == TW_Zero)
  616.     {
  617.       /* Number is zero */
  618.       l[0] = 0;
  619.       l[1] = 0;
  620.     }
  621.   else if (FPU_st0_tag == TW_Infinity)
  622.     {
  623.       l[0] = 0;
  624.       l[1] = 0x7ff00000;
  625.     }
  626.   else if (FPU_st0_tag == TW_NaN)
  627.     {
  628.       /* See if we can get a valid NaN from the FPU_REG */
  629.       l[0] = (FPU_st0_ptr->sigl >> 11) | (FPU_st0_ptr->sigh << 21);
  630.       l[1] = ((FPU_st0_ptr->sigh >> 11) & 0xfffff);
  631.       if ( !(FPU_st0_ptr->sigh & 0x40000000) )
  632.     {
  633.       /* It is a signalling NaN */
  634.       EXCEPTION(EX_Invalid);
  635.       if ( !(control_word & CW_Invalid) )
  636.         return 0;
  637.       l[1] |= (0x40000000 >> 11);
  638.     }
  639.       l[1] |= 0x7ff00000;
  640.     }
  641.   else if ( FPU_st0_tag == TW_Empty )
  642.     {
  643.       /* Empty register (stack underflow) */
  644.       EXCEPTION(EX_StackUnder);
  645.       if ( control_word & CW_Invalid )
  646.     {
  647.       /* The masked response */
  648.       /* Put out the QNaN indefinite */
  649.       RE_ENTRANT_CHECK_OFF;
  650.       FPU_verify_area(VERIFY_WRITE,(void *)dfloat,8);
  651.       put_fs_long(0, (unsigned long *) dfloat);
  652.       put_fs_long(0xfff80000, 1 + (unsigned long *) dfloat);
  653.       RE_ENTRANT_CHECK_ON;
  654.       return 1;
  655.     }
  656.       else
  657.     return 0;
  658.     }
  659.   if (FPU_st0_ptr->sign)
  660.     l[1] |= 0x80000000;
  661.  
  662.   RE_ENTRANT_CHECK_OFF;
  663.   FPU_verify_area(VERIFY_WRITE,(void *)dfloat,8);
  664.   put_fs_long(l[0], (unsigned long *)dfloat);
  665.   put_fs_long(l[1], 1 + (unsigned long *)dfloat);
  666.   RE_ENTRANT_CHECK_ON;
  667.  
  668.   return 1;
  669. }
  670.  
  671.  
  672. /* Put a float into user memory */
  673. int reg_store_single(void)
  674. {
  675.   float *single = (float *)FPU_data_address;
  676.   long templ;
  677.   unsigned long increment = 0;         /* avoid gcc warnings */
  678.  
  679.   if (FPU_st0_tag == TW_Valid)
  680.     {
  681.       int exp;
  682.       FPU_REG tmp;
  683.  
  684.       reg_move(FPU_st0_ptr, &tmp);
  685.       exp = tmp.exp - EXP_BIAS;
  686.  
  687.       if ( exp < SINGLE_Emin )
  688.     {
  689.       int precision_loss;
  690.  
  691.       /* A denormal will always underflow. */
  692. #ifndef PECULIAR_486
  693.       /* An 80486 is supposed to be able to generate
  694.          a denormal exception here, but... */
  695.       if ( FPU_st0_ptr->exp <= EXP_UNDER )
  696.         {
  697.           /* Underflow has priority. */
  698.           if ( control_word & CW_Underflow )
  699.         denormal_operand();
  700.         }
  701. #endif PECULIAR_486
  702.  
  703.       tmp.exp += -SINGLE_Emin + 23;  /* largest exp to be 22 */
  704.  
  705.       if ( (precision_loss = round_to_int(&tmp)) )
  706.         {
  707. #ifdef PECULIAR_486
  708.           /* Did it round to a non-denormal ? */
  709.           /* This behaviour might be regarded as peculiar, it appears
  710.          that the 80486 rounds to the dest precision, then
  711.          converts to decide underflow. */
  712.           if ( !((tmp.sigl == 0x00800000) &&
  713.           ((FPU_st0_ptr->sigh & 0x000000ff) || FPU_st0_ptr->sigl)) )
  714. #endif PECULIAR_486
  715.         {
  716.           EXCEPTION(EX_Underflow);
  717.           /* This is a special case: see sec 16.2.5.1 of
  718.              the 80486 book */
  719.           if ( !(control_word & EX_Underflow) )
  720.             return 0;
  721.         }
  722.           EXCEPTION(precision_loss);
  723.           if ( !(control_word & EX_Precision) )
  724.         return 0;
  725.         }
  726.       templ = tmp.sigl;
  727.     }
  728.       else
  729.     {
  730.       if ( tmp.sigl | (tmp.sigh & 0x000000ff) )
  731.         {
  732.           unsigned long sigh = tmp.sigh;
  733.           unsigned long sigl = tmp.sigl;
  734.           
  735.           switch (control_word & CW_RC)
  736.         {
  737.         case RC_RND:
  738.           increment = ((sigh & 0xff) > 0x80)       /* more than half */
  739.             || (((sigh & 0xff) == 0x80) && sigl)   /* more than half */
  740.               || ((sigh & 0x180) == 0x180);        /* round to even */
  741.           break;
  742.         case RC_DOWN:   /* towards -infinity */
  743.           increment = (tmp.sign == SIGN_POS)
  744.                       ? 0 : (sigl | (sigh & 0xff));
  745.           break;
  746.         case RC_UP:     /* towards +infinity */
  747.           increment = (tmp.sign == SIGN_POS)
  748.                       ? (sigl | (sigh & 0xff)) : 0;
  749.           break;
  750.         case RC_CHOP:
  751.           increment = 0;
  752.           break;
  753.         }
  754.       
  755.           /* Truncate part of the mantissa */
  756.           tmp.sigl = 0;
  757.       
  758.           if (increment)
  759.         {
  760.           set_precision_flag_up();
  761.  
  762.           if ( sigh >= 0xffffff00 )
  763.             {
  764.               /* The sigh part overflows */
  765.               tmp.sigh = 0x80000000;
  766.               exp++;
  767.               if ( exp >= EXP_OVER )
  768.             goto overflow;
  769.             }
  770.           else
  771.             {
  772.               tmp.sigh &= 0xffffff00;
  773.               tmp.sigh += 0x100;
  774.             }
  775.         }
  776.           else
  777.         {
  778.           set_precision_flag_down();
  779.           tmp.sigh &= 0xffffff00;  /* Finish the truncation */
  780.         }
  781.         }
  782.  
  783.       templ = (tmp.sigh >> 8) & 0x007fffff;
  784.  
  785.       if ( exp > SINGLE_Emax )
  786.         {
  787.         overflow:
  788.           EXCEPTION(EX_Overflow);
  789.           if ( !(control_word & CW_Overflow) )
  790.         return 0;
  791.           set_precision_flag_up();
  792.           if ( !(control_word & CW_Precision) )
  793.         return 0;
  794.  
  795.           /* This is a special case: see sec 16.2.5.1 of the 80486 book. */
  796.           /* Masked respose is overflow to infinity. */
  797.           templ = 0x7f800000;
  798.         }
  799.       else
  800.         templ |= ((exp+SINGLE_Ebias) & 0xff) << 23;
  801.     }
  802.     }
  803.   else if (FPU_st0_tag == TW_Zero)
  804.     {
  805.       templ = 0;
  806.     }
  807.   else if (FPU_st0_tag == TW_Infinity)
  808.     {
  809.       templ = 0x7f800000;
  810.     }
  811.   else if (FPU_st0_tag == TW_NaN)
  812.     {
  813.       /* See if we can get a valid NaN from the FPU_REG */
  814.       templ = FPU_st0_ptr->sigh >> 8;
  815.       if ( !(FPU_st0_ptr->sigh & 0x40000000) )
  816.     {
  817.       /* It is a signalling NaN */
  818.       EXCEPTION(EX_Invalid);
  819.       if ( !(control_word & CW_Invalid) )
  820.         return 0;
  821.       templ |= (0x40000000 >> 8);
  822.     }
  823.       templ |= 0x7f800000;
  824.     }
  825.   else if ( FPU_st0_tag == TW_Empty )
  826.     {
  827.       /* Empty register (stack underflow) */
  828.       EXCEPTION(EX_StackUnder);
  829.       if ( control_word & EX_Invalid )
  830.     {
  831.       /* The masked response */
  832.       /* Put out the QNaN indefinite */
  833.       RE_ENTRANT_CHECK_OFF;
  834.       FPU_verify_area(VERIFY_WRITE,(void *)single,4);
  835.       put_fs_long(0xffc00000, (unsigned long *) single);
  836.       RE_ENTRANT_CHECK_ON;
  837.       return 1;
  838.     }
  839.       else
  840.     return 0;
  841.     }
  842. #ifdef PARANOID
  843.   else
  844.     {
  845.       EXCEPTION(EX_INTERNAL|0x106);
  846.       return 0;
  847.     }
  848. #endif
  849.   if (FPU_st0_ptr->sign)
  850.     templ |= 0x80000000;
  851.  
  852.   RE_ENTRANT_CHECK_OFF;
  853.   FPU_verify_area(VERIFY_WRITE,(void *)single,4);
  854.   put_fs_long(templ,(unsigned long *) single);
  855.   RE_ENTRANT_CHECK_ON;
  856.  
  857.   return 1;
  858. }
  859.  
  860.  
  861. /* Put a long long into user memory */
  862. int reg_store_int64(void)
  863. {
  864.   long long *d = (long long *)FPU_data_address;
  865.   FPU_REG t;
  866.   long long tll;
  867.   int precision_loss;
  868.  
  869.   if ( FPU_st0_tag == TW_Empty )
  870.     {
  871.       /* Empty register (stack underflow) */
  872.       EXCEPTION(EX_StackUnder);
  873.       goto invalid_operand;
  874.     }
  875.   else if ( (FPU_st0_tag == TW_Infinity) ||
  876.        (FPU_st0_tag == TW_NaN) )
  877.     {
  878.       EXCEPTION(EX_Invalid);
  879.       goto invalid_operand;
  880.     }
  881.  
  882.   reg_move(FPU_st0_ptr, &t);
  883.   precision_loss = round_to_int(&t);
  884.   ((long *)&tll)[0] = t.sigl;
  885.   ((long *)&tll)[1] = t.sigh;
  886.   if ( (precision_loss == 1) ||
  887.       ((t.sigh & 0x80000000) &&
  888.        !((t.sigh == 0x80000000) && (t.sigl == 0) &&
  889.      (t.sign == SIGN_NEG))) )
  890.     {
  891.       EXCEPTION(EX_Invalid);
  892.       /* This is a special case: see sec 16.2.5.1 of the 80486 book */
  893.     invalid_operand:
  894.       if ( control_word & EX_Invalid )
  895.     {
  896.       /* Produce something like QNaN "indefinite" */
  897.       tll = 0x8000000000000000LL;
  898.     }
  899.       else
  900.     return 0;
  901.     }
  902.   else
  903.     {
  904.       if ( precision_loss )
  905.     set_precision_flag(precision_loss);
  906.       if ( t.sign )
  907.     tll = - tll;
  908.     }
  909.  
  910.   RE_ENTRANT_CHECK_OFF;
  911.   FPU_verify_area(VERIFY_WRITE,(void *)d,8);
  912.   put_fs_long(((long *)&tll)[0],(unsigned long *) d);
  913.   put_fs_long(((long *)&tll)[1],1 + (unsigned long *) d);
  914.   RE_ENTRANT_CHECK_ON;
  915.  
  916.   return 1;
  917. }
  918.  
  919.  
  920. /* Put a long into user memory */
  921. int reg_store_int32(void)
  922. {
  923.   long *d = (long *)FPU_data_address;
  924.   FPU_REG t;
  925.   int precision_loss;
  926.  
  927.   if ( FPU_st0_tag == TW_Empty )
  928.     {
  929.       /* Empty register (stack underflow) */
  930.       EXCEPTION(EX_StackUnder);
  931.       goto invalid_operand;
  932.     }
  933.   else if ( (FPU_st0_tag == TW_Infinity) ||
  934.        (FPU_st0_tag == TW_NaN) )
  935.     {
  936.       EXCEPTION(EX_Invalid);
  937.       goto invalid_operand;
  938.     }
  939.  
  940.   reg_move(FPU_st0_ptr, &t);
  941.   precision_loss = round_to_int(&t);
  942.   if (t.sigh ||
  943.       ((t.sigl & 0x80000000) &&
  944.        !((t.sigl == 0x80000000) && (t.sign == SIGN_NEG))) )
  945.     {
  946.       EXCEPTION(EX_Invalid);
  947.       /* This is a special case: see sec 16.2.5.1 of the 80486 book */
  948.     invalid_operand:
  949.       if ( control_word & EX_Invalid )
  950.     {
  951.       /* Produce something like QNaN "indefinite" */
  952.       t.sigl = 0x80000000;
  953.     }
  954.       else
  955.     return 0;
  956.     }
  957.   else
  958.     {
  959.       if ( precision_loss )
  960.     set_precision_flag(precision_loss);
  961.       if ( t.sign )
  962.     t.sigl = -(long)t.sigl;
  963.     }
  964.  
  965.   RE_ENTRANT_CHECK_OFF;
  966.   FPU_verify_area(VERIFY_WRITE,d,4);
  967.   put_fs_long(t.sigl, (unsigned long *) d);
  968.   RE_ENTRANT_CHECK_ON;
  969.  
  970.   return 1;
  971. }
  972.  
  973.  
  974. /* Put a short into user memory */
  975. int reg_store_int16(void)
  976. {
  977.   short *d = (short *)FPU_data_address;
  978.   FPU_REG t;
  979.   int precision_loss;
  980.  
  981.   if ( FPU_st0_tag == TW_Empty )
  982.     {
  983.       /* Empty register (stack underflow) */
  984.       EXCEPTION(EX_StackUnder);
  985.       goto invalid_operand;
  986.     }
  987.   else if ( (FPU_st0_tag == TW_Infinity) ||
  988.        (FPU_st0_tag == TW_NaN) )
  989.     {
  990.       EXCEPTION(EX_Invalid);
  991.       goto invalid_operand;
  992.     }
  993.  
  994.   reg_move(FPU_st0_ptr, &t);
  995.   precision_loss = round_to_int(&t);
  996.   if (t.sigh ||
  997.       ((t.sigl & 0xffff8000) &&
  998.        !((t.sigl == 0x8000) && (t.sign == SIGN_NEG))) )
  999.     {
  1000.       EXCEPTION(EX_Invalid);
  1001.       /* This is a special case: see sec 16.2.5.1 of the 80486 book */
  1002.     invalid_operand:
  1003.       if ( control_word & EX_Invalid )
  1004.     {
  1005.       /* Produce something like QNaN "indefinite" */
  1006.       t.sigl = 0x8000;
  1007.     }
  1008.       else
  1009.     return 0;
  1010.     }
  1011.   else
  1012.     {
  1013.       if ( precision_loss )
  1014.     set_precision_flag(precision_loss);
  1015.       if ( t.sign )
  1016.     t.sigl = -t.sigl;
  1017.     }
  1018.  
  1019.   RE_ENTRANT_CHECK_OFF;
  1020.   FPU_verify_area(VERIFY_WRITE,d,2);
  1021.   put_fs_word((short)t.sigl,(short *) d);
  1022.   RE_ENTRANT_CHECK_ON;
  1023.  
  1024.   return 1;
  1025. }
  1026.  
  1027.  
  1028. /* Put a packed bcd array into user memory */
  1029. int reg_store_bcd(void)
  1030. {
  1031.   char *d = (char *)FPU_data_address;
  1032.   FPU_REG t;
  1033.   unsigned long long ll;
  1034.   unsigned char b;
  1035.   int i, precision_loss;
  1036.   unsigned char sign = (FPU_st0_ptr->sign == SIGN_NEG) ? 0x80 : 0;
  1037.  
  1038.   if ( FPU_st0_tag == TW_Empty )
  1039.     {
  1040.       /* Empty register (stack underflow) */
  1041.       EXCEPTION(EX_StackUnder);
  1042.       goto invalid_operand;
  1043.     }
  1044.  
  1045.   reg_move(FPU_st0_ptr, &t);
  1046.   precision_loss = round_to_int(&t);
  1047.   ll = significand(&t);
  1048.  
  1049.   /* Check for overflow, by comparing with 999999999999999999 decimal. */
  1050.   if ( (t.sigh > 0x0de0b6b3) ||
  1051.       ((t.sigh == 0x0de0b6b3) && (t.sigl > 0xa763ffff)) )
  1052.     {
  1053.       EXCEPTION(EX_Invalid);
  1054.       /* This is a special case: see sec 16.2.5.1 of the 80486 book */
  1055.     invalid_operand:
  1056.       if ( control_word & CW_Invalid )
  1057.     {
  1058.       /* Produce the QNaN "indefinite" */
  1059.       RE_ENTRANT_CHECK_OFF;
  1060.       FPU_verify_area(VERIFY_WRITE,d,10);
  1061.       for ( i = 0; i < 7; i++)
  1062.         put_fs_byte(0, (unsigned char *) d+i); /* These bytes "undefined" */
  1063.       put_fs_byte(0xc0, (unsigned char *) d+7); /* This byte "undefined" */
  1064.       put_fs_byte(0xff, (unsigned char *) d+8);
  1065.       put_fs_byte(0xff, (unsigned char *) d+9);
  1066.       RE_ENTRANT_CHECK_ON;
  1067.       return 1;
  1068.     }
  1069.       else
  1070.     return 0;
  1071.     }
  1072.   else if ( precision_loss )
  1073.     {
  1074.       /* Precision loss doesn't stop the data transfer */
  1075.       set_precision_flag(precision_loss);
  1076.     }
  1077.  
  1078.   RE_ENTRANT_CHECK_OFF;
  1079.   FPU_verify_area(VERIFY_WRITE,d,10);
  1080.   RE_ENTRANT_CHECK_ON;
  1081.   for ( i = 0; i < 9; i++)
  1082.     {
  1083.       b = div_small(&ll, 10);
  1084.       b |= (div_small(&ll, 10)) << 4;
  1085.       RE_ENTRANT_CHECK_OFF;
  1086.       put_fs_byte(b,(unsigned char *) d+i);
  1087.       RE_ENTRANT_CHECK_ON;
  1088.     }
  1089.   RE_ENTRANT_CHECK_OFF;
  1090.   put_fs_byte(sign,(unsigned char *) d+9);
  1091.   RE_ENTRANT_CHECK_ON;
  1092.  
  1093.   return 1;
  1094. }
  1095.  
  1096. /*===========================================================================*/
  1097.  
  1098. /* r gets mangled such that sig is int, sign: 
  1099.    it is NOT normalized */
  1100. /* The return value (in eax) is zero if the result is exact,
  1101.    if bits are changed due to rounding, truncation, etc, then
  1102.    a non-zero value is returned */
  1103. /* Overflow is signalled by a non-zero return value (in eax).
  1104.    In the case of overflow, the returned significand always has the
  1105.    the largest possible value */
  1106. int round_to_int(FPU_REG *r)
  1107. {
  1108.   char     very_big;
  1109.   unsigned eax;
  1110.  
  1111.   if (r->tag == TW_Zero)
  1112.     {
  1113.       /* Make sure that zero is returned */
  1114.       significand(r) = 0;
  1115.       return 0;        /* o.k. */
  1116.     }
  1117.   
  1118.   if (r->exp > EXP_BIAS + 63)
  1119.     {
  1120.       r->sigl = r->sigh = ~0;      /* The largest representable number */
  1121.       return 1;        /* overflow */
  1122.     }
  1123.  
  1124.   eax = shrxs(&r->sigl, EXP_BIAS + 63 - r->exp);
  1125.   very_big = !(~(r->sigh) | ~(r->sigl));  /* test for 0xfff...fff */
  1126. #define    half_or_more    (eax & 0x80000000)
  1127. #define    frac_part    (eax)
  1128. #define more_than_half  ((eax & 0x80000001) == 0x80000001)
  1129.   switch (control_word & CW_RC)
  1130.     {
  1131.     case RC_RND:
  1132.       if ( more_than_half                   /* nearest */
  1133.       || (half_or_more && (r->sigl & 1)) )    /* odd -> even */
  1134.     {
  1135.       if ( very_big ) return 1;        /* overflow */
  1136.       significand(r) ++;
  1137.       return PRECISION_LOST_UP;
  1138.     }
  1139.       break;
  1140.     case RC_DOWN:
  1141.       if (frac_part && r->sign)
  1142.     {
  1143.       if ( very_big ) return 1;        /* overflow */
  1144.       significand(r) ++;
  1145.       return PRECISION_LOST_UP;
  1146.     }
  1147.       break;
  1148.     case RC_UP:
  1149.       if (frac_part && !r->sign)
  1150.     {
  1151.       if ( very_big ) return 1;        /* overflow */
  1152.       significand(r) ++;
  1153.       return PRECISION_LOST_UP;
  1154.     }
  1155.       break;
  1156.     case RC_CHOP:
  1157.       break;
  1158.     }
  1159.  
  1160.   return eax ? PRECISION_LOST_DOWN : 0;
  1161.  
  1162. }
  1163.  
  1164. /*===========================================================================*/
  1165.  
  1166. char *fldenv(fpu_addr_modes addr_modes)
  1167. {
  1168.   char *s = (char *)FPU_data_address;
  1169.   unsigned short tag_word = 0;
  1170.   unsigned char tag;
  1171.   int i;
  1172.  
  1173.   if ( addr_modes.vm86
  1174.       || (addr_modes.override.operand_size == OP_SIZE_PREFIX) )
  1175.     {
  1176.       RE_ENTRANT_CHECK_OFF;
  1177.       FPU_verify_area(VERIFY_READ, s, 0x0e);
  1178.       control_word = get_fs_word((unsigned short *) s);
  1179.       partial_status = get_fs_word((unsigned short *) (s+2));
  1180.       tag_word = get_fs_word((unsigned short *) (s+4));
  1181.       ip_offset = get_fs_word((unsigned short *) (s+6));
  1182.       cs_selector = get_fs_word((unsigned short *) (s+8));
  1183.       data_operand_offset = get_fs_word((unsigned short *) (s+0x0a));
  1184.       operand_selector = get_fs_word((unsigned short *) (s+0x0c));
  1185.       RE_ENTRANT_CHECK_ON;
  1186.       s += 0x0e;
  1187.       if ( addr_modes.vm86 )
  1188.     {
  1189.       ip_offset += (cs_selector & 0xf000) << 4;
  1190.       data_operand_offset += (operand_selector & 0xf000) << 4;
  1191.     }
  1192.     }
  1193.   else
  1194.     {
  1195.       RE_ENTRANT_CHECK_OFF;
  1196.       FPU_verify_area(VERIFY_READ, s, 0x1c);
  1197.       control_word = get_fs_word((unsigned short *) s);
  1198.       partial_status = get_fs_word((unsigned short *) (s+4));
  1199.       tag_word = get_fs_word((unsigned short *) (s+8));
  1200.       ip_offset = get_fs_long((unsigned long *) (s+0x0c));
  1201.       cs_selector = get_fs_long((unsigned long *) (s+0x10));
  1202.       data_operand_offset = get_fs_long((unsigned long *) (s+0x14));
  1203.       operand_selector = get_fs_long((unsigned long *) (s+0x18));
  1204.       RE_ENTRANT_CHECK_ON;
  1205.       s += 0x1c;
  1206.     }
  1207.  
  1208. #ifdef PECULIAR_486
  1209.   control_word &= ~0xe080;
  1210. #endif PECULIAR_486
  1211.  
  1212.   top = (partial_status >> SW_Top_Shift) & 7;
  1213.  
  1214.   if ( partial_status & ~control_word & CW_Exceptions )
  1215.     partial_status |= (SW_Summary | SW_Backward);
  1216.   else
  1217.     partial_status &= ~(SW_Summary | SW_Backward);
  1218.  
  1219.   for ( i = 0; i < 8; i++ )
  1220.     {
  1221.       tag = tag_word & 3;
  1222.       tag_word >>= 2;
  1223.  
  1224.       if ( tag == 3 )
  1225.     /* New tag is empty.  Accept it */
  1226.     regs[i].tag = TW_Empty;
  1227.       else if ( regs[i].tag == TW_Empty )
  1228.     {
  1229.       /* Old tag is empty and new tag is not empty.  New tag is determined
  1230.          by old reg contents */
  1231.       if ( regs[i].exp == EXP_BIAS - EXTENDED_Ebias )
  1232.         {
  1233.           if ( !(regs[i].sigl | regs[i].sigh) )
  1234.         regs[i].tag = TW_Zero;
  1235.           else
  1236.         regs[i].tag = TW_Valid;
  1237.         }
  1238.       else if ( regs[i].exp == 0x7fff + EXP_BIAS - EXTENDED_Ebias )
  1239.         {
  1240.           if ( !((regs[i].sigh & ~0x80000000) | regs[i].sigl) )
  1241.         regs[i].tag = TW_Infinity;
  1242.           else
  1243.         regs[i].tag = TW_NaN;
  1244.         }
  1245.       else
  1246.         regs[i].tag = TW_Valid;
  1247.       }
  1248.       /* Else old tag is not empty and new tag is not empty.  Old tag
  1249.      remains correct */
  1250.     }
  1251.  
  1252.   /* Ensure that the values just loaded are not changed by
  1253.      fix-up operations. */
  1254.   NO_NET_DATA_EFFECT;
  1255.   NO_NET_INSTR_EFFECT;
  1256.  
  1257.   return s;
  1258. }
  1259.  
  1260.  
  1261. void frstor(fpu_addr_modes addr_modes)
  1262. {
  1263.   int i, stnr;
  1264.   unsigned char tag;
  1265.   char *s = fldenv(addr_modes);
  1266.  
  1267.   for ( i = 0; i < 8; i++ )
  1268.     {
  1269.       /* Load each register. */
  1270.       FPU_data_address = (void *)(s+i*10);
  1271.       reg_load_extended();
  1272.       stnr = (i+top) & 7;
  1273.       tag = regs[stnr].tag;   /* Derived from the loaded tag word. */
  1274.       reg_move(&FPU_loaded_data, ®s[stnr]);
  1275.       if ( tag == TW_Empty )  /* The loaded data over-rides all other cases. */
  1276.     regs[stnr].tag = tag;
  1277.     }
  1278.  
  1279.   /* Reverse the effect which loading the registers had on the
  1280.      data pointer */
  1281.   NO_NET_DATA_EFFECT;
  1282.  
  1283. }
  1284.  
  1285.  
  1286. unsigned short tag_word(void)
  1287. {
  1288.   unsigned short word = 0;
  1289.   unsigned char tag;
  1290.   int i;
  1291.  
  1292.   for ( i = 7; i >= 0; i-- )
  1293.     {
  1294.       switch ( tag = regs[i].tag )
  1295.     {
  1296.     case TW_Valid:
  1297.       if ( regs[i].exp <= (EXP_BIAS - EXTENDED_Ebias) )
  1298.         tag = 2;
  1299.       break;
  1300.     case TW_Infinity:
  1301.     case TW_NaN:
  1302.       tag = 2;
  1303.       break;
  1304.     case TW_Empty:
  1305.       tag = 3;
  1306.       break;
  1307.       /* TW_Zero already has the correct value */
  1308.     }
  1309.       word <<= 2;
  1310.       word |= tag;
  1311.     }
  1312.   return word;
  1313. }
  1314.  
  1315.  
  1316. char *fstenv(fpu_addr_modes addr_modes)
  1317. {
  1318.   char *d = (char *)FPU_data_address;
  1319.  
  1320.   if ( addr_modes.vm86
  1321.       || (addr_modes.override.operand_size == OP_SIZE_PREFIX) )
  1322.     {
  1323.       RE_ENTRANT_CHECK_OFF;
  1324.       FPU_verify_area(VERIFY_WRITE,d,14);
  1325. #ifdef PECULIAR_486
  1326.       put_fs_long(control_word & ~0xe080, (unsigned short *) d);
  1327. #else
  1328.       put_fs_word(control_word, (unsigned short *) d);
  1329. #endif PECULIAR_486
  1330.       put_fs_word(status_word(), (unsigned short *) (d+2));
  1331.       put_fs_word(tag_word(), (unsigned short *) (d+4));
  1332.       put_fs_word(ip_offset, (unsigned short *) (d+6));
  1333.       put_fs_word(data_operand_offset, (unsigned short *) (d+0x0a));
  1334.       if ( addr_modes.vm86 )
  1335.     {
  1336.       put_fs_word((ip_offset & 0xf0000) >> 4,
  1337.               (unsigned short *) (d+8));
  1338.       put_fs_word((data_operand_offset & 0xf0000) >> 4,
  1339.               (unsigned short *) (d+0x0c));
  1340.     }
  1341.       else
  1342.     {
  1343.       put_fs_word(cs_selector, (unsigned short *) (d+8));
  1344.       put_fs_word(operand_selector, (unsigned short *) (d+0x0c));
  1345.     }
  1346.       RE_ENTRANT_CHECK_ON;
  1347.       d += 0x0e;
  1348.     }
  1349.   else
  1350.     {
  1351.       RE_ENTRANT_CHECK_OFF;
  1352.       FPU_verify_area(VERIFY_WRITE,d,28);
  1353. #ifdef PECULIAR_486
  1354.       /* An 80486 sets all the reserved bits to 1. */
  1355.       put_fs_long(0xffff0040 | (control_word & ~0xe080), (unsigned long *) d);
  1356.       put_fs_long(0xffff0000 | status_word(), (unsigned long *) (d+4));
  1357.       put_fs_long(0xffff0000 | tag_word(), (unsigned long *) (d+8));
  1358. #else
  1359.       put_fs_word(control_word, (unsigned short *) d);
  1360.       put_fs_word(status_word(), (unsigned short *) (d+4));
  1361.       put_fs_word(tag_word(), (unsigned short *) (d+8));
  1362. #endif PECULIAR_486
  1363.       put_fs_long(ip_offset, (unsigned long *) (d+0x0c));
  1364.       put_fs_long(cs_selector & ~0xf8000000, (unsigned long *) (d+0x10));
  1365.       put_fs_long(data_operand_offset, (unsigned long *) (d+0x14));
  1366. #ifdef PECULIAR_486
  1367.       /* An 80486 sets all the reserved bits to 1. */
  1368.       put_fs_long(0xffff0000 | operand_selector, (unsigned long *) (d+0x18));
  1369. #else
  1370.       put_fs_long(operand_selector, (unsigned long *) (d+0x18));
  1371. #endif PECULIAR_486
  1372.       RE_ENTRANT_CHECK_ON;
  1373.       d += 0x1c;
  1374.     }
  1375.   
  1376.   control_word |= CW_Exceptions;
  1377.   partial_status &= ~(SW_Summary | SW_Backward);
  1378.  
  1379.   return d;
  1380. }
  1381.  
  1382.  
  1383. void fsave(fpu_addr_modes addr_modes)
  1384. {
  1385.   char *d;
  1386.   int i;
  1387.  
  1388.   d = fstenv(addr_modes);
  1389.   RE_ENTRANT_CHECK_OFF;
  1390.   FPU_verify_area(VERIFY_WRITE,d,80);
  1391.   RE_ENTRANT_CHECK_ON;
  1392.   for ( i = 0; i < 8; i++ )
  1393.     write_to_extended(®s[(top + i) & 7], d + 10 * i);
  1394.  
  1395.   finit();
  1396.  
  1397. }
  1398.  
  1399. /*===========================================================================*/
  1400.  
  1401. /*
  1402.   A call to this function must be preceeded by a call to
  1403.   FPU_verify_area() to verify access to the 10 bytes at d
  1404.   */
  1405. static void write_to_extended(FPU_REG *rp, char *d)
  1406. {
  1407.   long e;
  1408.   FPU_REG tmp;
  1409.   
  1410.   e = rp->exp - EXP_BIAS + EXTENDED_Ebias;
  1411.  
  1412. #ifdef PARANOID
  1413.   switch ( rp->tag )
  1414.     {
  1415.     case TW_Zero:
  1416.       if ( rp->sigh | rp->sigl | e )
  1417.     EXCEPTION(EX_INTERNAL | 0x114);
  1418.       break;
  1419.     case TW_Infinity:
  1420.     case TW_NaN:
  1421.       if ( (e ^ 0x7fff) | !(rp->sigh & 0x80000000) )
  1422.     EXCEPTION(EX_INTERNAL | 0x114);
  1423.       break;
  1424.     default:
  1425.       if (e > 0x7fff || e < -63)
  1426.     EXCEPTION(EX_INTERNAL | 0x114);
  1427.     }
  1428. #endif PARANOID
  1429.  
  1430.   /*
  1431.     All numbers except denormals are stored internally in a
  1432.     format which is compatible with the extended real number
  1433.     format.
  1434.    */
  1435.   if ( e > 0 )
  1436.     {
  1437.       /* just copy the reg */
  1438.       RE_ENTRANT_CHECK_OFF;
  1439.       put_fs_long(rp->sigl, (unsigned long *) d);
  1440.       put_fs_long(rp->sigh, (unsigned long *) (d + 4));
  1441.       RE_ENTRANT_CHECK_ON;
  1442.     }
  1443.   else
  1444.     {
  1445.       /*
  1446.     The number is a de-normal stored as a normal using our
  1447.     extra exponent range, or is Zero.
  1448.     Convert it back to a de-normal, or leave it as Zero.
  1449.        */
  1450.       reg_move(rp, &tmp);
  1451.       tmp.exp += -EXTENDED_Emin + 63;  /* largest exp to be 63 */
  1452.       round_to_int(&tmp);
  1453.       e = 0;
  1454.       RE_ENTRANT_CHECK_OFF;
  1455.       put_fs_long(tmp.sigl, (unsigned long *) d);
  1456.       put_fs_long(tmp.sigh, (unsigned long *) (d + 4));
  1457.       RE_ENTRANT_CHECK_ON;
  1458.     }
  1459.   e |= rp->sign == SIGN_POS ? 0 : 0x8000;
  1460.   RE_ENTRANT_CHECK_OFF;
  1461.   put_fs_word(e, (unsigned short *) (d + 8));
  1462.   RE_ENTRANT_CHECK_ON;
  1463. }
  1464.